/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.papillion39.sechelper.test.adduser;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.security.SecureRandom;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.swing.AbstractListModel;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.LayoutStyle;
import javax.swing.SwingWorker;
import javax.swing.WindowConstants;

/**
 *
 * @author Jonathan Paz <jonathan.paz@ottr.com>
 */
public class AddUser extends javax.swing.JFrame {

    /**
     * Creates new form AddUser
     */
    public AddUser() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jLabel1 = new JLabel();
        jLabel2 = new JLabel();
        jLabel3 = new JLabel();
        userName = new JTextField();
        password = new JPasswordField();
        confirmPassword = new JPasswordField();
        jButton1 = new JButton();
        jLabel4 = new JLabel();
        firstName = new JTextField();
        jLabel6 = new JLabel();
        lastName = new JTextField();
        jScrollPane2 = new JScrollPane();
        roles = new JList();
        jLabel7 = new JLabel();

        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        jLabel1.setText("User Name");

        jLabel2.setText("Password");

        jLabel3.setText("Confirm");

        jButton1.setText("Ok");
        jButton1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jLabel4.setText("First Name");

        jLabel6.setText("Last Name");

        roles.setModel(new AbstractListModel() {
            String[] strings = { "User", "Distributor", "Secretary" };
            public int getSize() { return strings.length; }
            public Object getElementAt(int i) { return strings[i]; }
        });
        jScrollPane2.setViewportView(roles);

        jLabel7.setText("Roles");

        GroupLayout layout = new GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(0, 0, Short.MAX_VALUE)
                        .addComponent(jButton1))
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel2)
                            .addComponent(jLabel3)
                            .addComponent(jLabel4)
                            .addComponent(jLabel1)
                            .addComponent(jLabel6)
                            .addComponent(jLabel7))
                        .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                            .addComponent(confirmPassword)
                            .addComponent(userName)
                            .addComponent(password)
                            .addComponent(firstName)
                            .addComponent(jScrollPane2, GroupLayout.DEFAULT_SIZE, 318, Short.MAX_VALUE)
                            .addComponent(lastName))))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel4)
                    .addComponent(firstName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel6)
                    .addComponent(lastName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                    .addComponent(userName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel1))
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                    .addComponent(password, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel2))
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                    .addComponent(confirmPassword, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel3))
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel7)
                    .addComponent(jScrollPane2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, Short.MAX_VALUE)
                .addComponent(jButton1)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jButton1ActionPerformed(ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        if (Arrays.equals(password.getPassword(), confirmPassword.getPassword())) {
            new AddUserToDatabase(firstName.getText(),lastName.getText(),userName.getText(), password.getPassword(), roles.getSelectedValuesList()).execute();
        } else {
            JOptionPane.showMessageDialog(this, "Passwords do not match", "Password Error", JOptionPane.WARNING_MESSAGE);
        }
    }//GEN-LAST:event_jButton1ActionPerformed

    private class AddUserToDatabase extends SwingWorker<Boolean,String> {
        private final String firstName, lastName, userName;
        private final char[] password;
        private final List<String> roles;
        AddUserToDatabase(String firstName, String lastName, String userName, char[] password, List<String> roles) {
            this.firstName = firstName;
            this.lastName = lastName;
            this.userName = userName;
            this.password = password;
            this.roles = roles;
        }

        @Override
        protected void done() {
            try {
                if (get()) {
                    JOptionPane.showMessageDialog(AddUser.this, "Success!!", "Success", JOptionPane.INFORMATION_MESSAGE);
                }
            } catch (ExecutionException | InterruptedException e) {
                JOptionPane.showMessageDialog(AddUser.this, new Object[]{e.getMessage(), e.getStackTrace()},"Exception", JOptionPane.ERROR_MESSAGE);
            }
        }

        @Override
        protected Boolean doInBackground() throws Exception {
            byte[] salt = new byte[256/8];
            new SecureRandom().nextBytes(salt);
            SecretKeyFactory fac = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            PBEKeySpec spec = new PBEKeySpec(password, salt, 4096, 256);
            byte[] pwd = fac.generateSecret(spec).getEncoded();

            try (Connection c = DriverManager.getConnection("jdbc:postgresql://localhost:5432/sechelper","sechelper","sechelper")) {
                c.setAutoCommit(false);
                int personId, accountId;
                try {
                    try (PreparedStatement stmt = c.prepareStatement("insert into person (first_name, last_name) values (?,?)", Statement.RETURN_GENERATED_KEYS)){
                        stmt.setString(1, firstName);
                        stmt.setString(2, lastName);
                        stmt.executeUpdate();
                        try (ResultSet rs = stmt.getGeneratedKeys()) {
                            if (rs.next()) {
                                personId = rs.getInt(1);
                            } else {
                                throw new Exception("No auto-generated key was made");
                            }
                        }
                    }
                    try (PreparedStatement stmt = c.prepareStatement("insert into account(person_id,user_name, password, salt) values (?,?,?,?)", Statement.RETURN_GENERATED_KEYS)) {
                        stmt.setInt(1,personId);
                        stmt.setString(2, userName);
                        stmt.setBytes(3, pwd);
                        stmt.setBytes(4, salt);
                        stmt.executeUpdate();
                        try (ResultSet rs = stmt.getGeneratedKeys()) {
                            if (rs.next()) {
                                accountId = rs.getInt(1);
                            } else {
                                throw new Exception("No auto-generated key was made");
                            }
                        }
                    }
                    try (PreparedStatement stmt = c.prepareStatement("insert into account_role_group (account_id,role_group_id) select ?,id from role_group where name = ?")) {
                        for (String role : roles) {
                            stmt.setInt(1, accountId);
                            stmt.setString(2,role);
                            stmt.executeUpdate();
                        }
                    }
                    c.commit();
                } finally {
                    c.rollback();
                    c.setAutoCommit(true);
                }
            }
            return true;
        }

    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(AddUser.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(() -> {
            new AddUser().setVisible(true);
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private JPasswordField confirmPassword;
    private JTextField firstName;
    private JButton jButton1;
    private JLabel jLabel1;
    private JLabel jLabel2;
    private JLabel jLabel3;
    private JLabel jLabel4;
    private JLabel jLabel6;
    private JLabel jLabel7;
    private JScrollPane jScrollPane2;
    private JTextField lastName;
    private JPasswordField password;
    private JList roles;
    private JTextField userName;
    // End of variables declaration//GEN-END:variables
}
